/*
 * TIM2-CC.c
 *
 *  Created on: Nov 15, 2013
 *      Author: Ahmed
 */

#include "stm32f10x.h"
#include "main.h"
#include "TIM2CH2.h"

/* Private variables ---------------------------------------------------------*/
	TIM_ICInitTypeDef  		TIM_ICInitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  		TIM_OCInitStructure;
/* Private function prototypes -----------------------------------------------*/
void RCC_Configuration(void);
//void GPIO_Configuration(void);
void TIM2_GPIO_Configuration(uint8_t);
void TIM2_NVIC_Configuration(void);


/*
 * TIM2_CH2 Alternate function on PA1 - Configure as input capture
 *
 * TIM_CH1 as Output Compare
 */

void TIM2_Configuration (){

	  /* System Clocks Configuration */
	  RCC_Configuration();

	  /* NVIC configuration */
	  TIM2_NVIC_Configuration();

	  /* Configure the GPIO ports */
	  TIM2_GPIO_Configuration(PA1_INPUT);

	  /* Time base configuration */
//	   TIM_TimeBaseStructure.TIM_Period = 65535;
	   TIM_TimeBaseStructure.TIM_Period = 8000-1;	// Counter overflow each 1ms based on a clock of 8MHz
	   TIM_TimeBaseStructure.TIM_Prescaler = 0;
	   TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

	   TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

	  /* TIM2 configuration: Input Capture mode ---------------------
	     The external signal is connected to TIM2 CH2 pin (PA.01)
	     The Rising/Falling edge is used as active edge,
	  ------------------------------------------------------------ */
	  TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
	  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
	  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
	  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;	// This prescaler is on the input capture level
	  TIM_ICInitStructure.TIM_ICFilter = 0x0;

	  TIM_ICInit(TIM2, &TIM_ICInitStructure);

	  /* TIM enable counter */
	  TIM_Cmd(TIM2, ENABLE);
}

/**
  * @brief  Configures the different system clocks.
  * @param  None
  * @retval None
  */
void RCC_Configuration(void)
{
  /* TIM2 clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  /* GPIOA clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
}

/**
  * @brief  Configure the GPIOA Pin for PA1 to be either output or TIM2_CH2 Capture input
  * @param  None
  * @retval None
  */
void TIM2_GPIO_Configuration(uint8_t mode)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* (PA.0) as output configuration to drive the sensor VCC */
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  if (mode == PA1_INPUT) {
	  /* TIM2 channel 2 pin (PA.01) alternate function configuration */
	  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_1;
	  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  } else {
	  /* (PA.01) as output configuration */
	  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_1;
	  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  }
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}

/**
  * @brief  Configure the nested vectored interrupt controller.
  * @param  None
  * @retval None
  */
void TIM2_NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  /* Enable the TIM2 global Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

/*
 * dht22.c
 *
 *  Created on: Nov 15, 2013
 *      Author: Ahmed
 */

/*
 * dht22.c
 *
 *  Created on: Dec 29, 2012
 *      Author: Home
 */

/*
 * This program will interface with the DHT22 Temperature and Humidity sensor using propriatory 1-wire
 * interface on Pin P1.0 and Timer A1
 * When MCU send start signal, RHT03 change from standby-status to running-status. When MCU finishs sending the
 * start signal, RHT03 will send response signal of 40-bit data that reflect the relative humidity and
 * temperature to MCU.
 * MCU will pull low data-bus and this process must beyond at least 1~10ms to ensure RHT03 could detect MCU's signal,
 * then MCU will pulls up and wait 20-40us for RHT03's response.
 * When RHT03 detect the start signal, RHT03 will pull low the bus 80us as response signal, then RHT03 pulls up
 * 80us for preparation to send data.
 *
 * DHT22 is connected to PA1 to read it through TIM2 CH2 capture mode
 * Data from DHT22 flow MSB to LSB, so the High byte (MSB) first then the Low byte of the 16 bit value of
 * Humidity and heat.
 * The information we need is represented in the high pulse durations.
 * Accordingly, we only care about measuring the high pulses duration only
 * 		-----------------------------------------------------------------------------
 * 		| This code runs at 8Mhz to ensure capturing the DHT22 pulse width correctly |
 * 		-----------------------------------------------------------------------------
 */

#define	DHT22_DATA_SIZE		5			// Size of the DHT22 data received in bytes (Hum 2, Temp 2 and checksum 1)
#define	DHT22_HIGH_DATA_THRESHOLD	100	// dht22 data high pulse duration threshold to decide on data being 0 or 1
										// The ZERO bit high pulse width is 80us and the ONE bit high pulse width
										// is 126us. So, the decision to decide if this is one or zero can be taken
										// at thresold 100us

typedef enum {DATA_ACK, FIRST_DATA_BIT, NEXT_DATA_BIT} DHT22_STATES;
DHT22_STATES dht22_state = DATA_ACK;

extern unsigned char dht22[5];
uint16_t new_cap=0;
uint16_t old_cap=0;
uint8_t bit_counter;			// keeps track of the data pulses parsed (maximum 40 bits)
uint8_t byte_counter;			// keeps track of the data pulses parsed (maximum 5 bytes)
uint32_t pulse_duration;		// duration in uS of the DHT22 generated pulse data

/*
 * TIM2 Interrupt Handler
 * - Read DHT22 sensor data stream in capture mode and store it in an array for later parsing
 * It only works on the falling edge
 */
void TIM2_CC_Handler (void)
{
/*
* We need here to decide if we came here due to rising or falling edge, and set the dht22_state value
* before going through the state machine
*/

	switch (dht22_state) {
		case DATA_ACK:							// we receive an Acknowldge pulse start from the DHT22
			dht22_state = FIRST_DATA_BIT;		// be ready to receive data pulses
												// Initialize DHT22 readings array
												// except checksum
			for (byte_counter = 0; byte_counter < DHT22_DATA_SIZE-1; byte_counter++) {
				dht22[byte_counter]=0;
			}
			dht22[byte_counter]=0xFF;			// Set checksum to 0xFF to ensure that
												// the checksum test does not succeed if all array
												// bytes were zeros.
			bit_counter = 0;					// reset DHT22 data bit counter within a byte
			byte_counter = 0;					// reset DHT22 data byte counter
			break;

		case FIRST_DATA_BIT:
			old_cap=TIM_GetCapture2(TIM2);		// Store the start of the first data bit
			dht22_state = NEXT_DATA_BIT;
			break;


		case NEXT_DATA_BIT:
			new_cap = TIM_GetCapture2(TIM2);	// Store current time stamp (timer value)
												// store the length of the previous pulse
												// Divide by 8 as the Timer Clock is 8Mhz
		    /* Capture computation */
		    if (new_cap > old_cap) {
		    	pulse_duration = (new_cap - old_cap)/8;
		    } else {
		    	pulse_duration = ((0xFFFF - old_cap) + new_cap)/8;
		    }
			dht22[byte_counter]<<=1;			// shift left to leave a space for the new bit
			if (pulse_duration > DHT22_HIGH_DATA_THRESHOLD){
				dht22[byte_counter] |= 1;	// This is a ONE bit
			} else {
				dht22[byte_counter] &= ~1;	// This is a ZERO bit
			}
			bit_counter++;					// We passed one date bit, then increment counter
			if (bit_counter == 8) {			// Finished filling one byte, then move to next byte
				byte_counter++;
				bit_counter = 0;
				if (byte_counter == DHT22_DATA_SIZE){
					dht22_state = DATA_ACK;// reset to the initial state
					break;
				}
			}
			old_cap = new_cap;
			break;

		default:
			break;
	}
}

/*
 * This function is called to reset the state machine of the DHT22 parser in case
 * a previous parsing was not successful
 */
void TIM2_DeInit (void){
	dht22_state = DATA_ACK;
}
